package com.xusheng.cli.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.xusheng.cli.common.exception.ServiceException;
import com.xusheng.cli.entity.paymentChannelModule.PaymentChannel;
import com.xusheng.cli.entity.withdrawModule.Withdraw;
import com.xusheng.cli.entity.withdrawModule.WithdrawReq;
import com.xusheng.cli.service.PayWithdrawService;
import com.xusheng.cli.service.PaymentChannelService;
import com.xusheng.cli.service.WithdrawService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

/**
 * 代付结算
 */
@Service("fakaPayHanderService")
@Slf4j
public class FakaPayHanderServiceImpl implements PayWithdrawService {
    @Resource
    private PaymentChannelService paymentChannelService;
    @Resource
    private WithdrawService withdrawService;
    @Resource
    private RedissonClient redissonClient;

    @Override
    public void createOrder(WithdrawReq req, HttpServletRequest request) {
        String returnUrl = request.getScheme() + "://" + request.getServerName();
        List<Withdraw> withdraws = withdrawService.lambdaQuery().in(Withdraw::getId, req.getIds()).list();
        if (CollectionUtil.isEmpty(withdraws)) {
            return;
        }
        // 获取代付通道
        PaymentChannel paymentChannel = paymentChannelService.lambdaQuery()
                .eq(PaymentChannel::getApiType, 2)
                .eq(PaymentChannel::getDefaultChannel, 1)
                .one();
        if (paymentChannel == null) {
            throw new ServiceException("请先设置结算通道");
        }
        for (Withdraw withdraw : withdraws) {
            //根据提现费率计算实际到账金额
            withdraw.setActualAmount(withdraw.getAmount());
            withdraw.setCharges(withdraw.getAmount().subtract(withdraw.getActualAmount()));
            // 修改订单状态为待处理
            withdraw.setState(2);
            withdraw.setPaymentChannelId(paymentChannel.getId());
            withdrawService.updateById(withdraw);
            RLock lock = redissonClient.getLock("withdraw:" + withdraw.getId());
            try {
                if (lock.tryLock(0, 5, TimeUnit.MINUTES)) {
                    orderCreate(withdraw, returnUrl, paymentChannel);
                }
            } catch (Exception e) {
                log.error("提现打款出错，订单信息：{}", withdraw, e);
            } finally {
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
    }

    private HttpResponse orderCreate(Withdraw withdraw, String returnUrl, PaymentChannel paymentChannel) {

        Map<String, String> reqParam = new TreeMap<>();
        reqParam.put("merchantId", paymentChannel.getMerchantNumber());
        reqParam.put("requestId", withdraw.getId().toString());
        reqParam.put("amount", withdraw.getActualAmount().multiply(BigDecimal.valueOf(100)).toString());// 代付金额,单位分
        reqParam.put("bankName", withdraw.getBankAccountName());
        reqParam.put("bankNumber", withdraw.getAccount());
        reqParam.put("bankType", withdraw.getBankName());
        reqParam.put("payKey", paymentChannel.getPassword());
        reqParam.put("notifyUrl", returnUrl.concat("/video-platform/api/v1/fakapay/paynotify"));
        String sign = getSign(reqParam, paymentChannel.getSecret());
        reqParam.put("code", sign);
        System.out.println(JSONUtil.toJsonStr(reqParam));
        Map<String, String> heads = new HashMap<>();

        heads.put("Content-Type", "application/json;charset=UTF-8");
        HttpResponse response = HttpRequest.post(paymentChannel.getHost() + "/api/v1/pay/repay")
                .headerMap(heads, false)
                .body(JSONUtil.toJsonStr(reqParam))
                .timeout(5 * 60 * 1000)
                .execute();
        log.info("返回结果========{}", response);
        return response;
    }

    public static String getSign(Map<String, String> reqParam, String key) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : reqParam.entrySet()) {
            if (!"code".equalsIgnoreCase(entry.getKey()) && StrUtil.isNotEmpty(entry.getValue())) {
                sb.append(entry.getValue()).append("&");
            }
        }
        String signOriginStr = sb.toString();
        signOriginStr += key;
        log.info("签名原文:{}", signOriginStr);
        String sign = null;
        try {
            sign = DigestUtils.md5Hex(signOriginStr.getBytes("UTF-8"));
        } catch (Exception e) {
            log.error("字符串进行MD5加密发生{}异常，具体错误描述:{}", e.getClass().getName(), e.getMessage());
        }

        if (StrUtil.isEmpty(sign)) {
            return null;
        }
        log.info("实际签名:{}", sign);
        return sign;
    }

    public static void main(String[] args) {
        Map<String, String> reqParam = new TreeMap<>();
        reqParam.put("merchantId", "sysAdmin");
        reqParam.put("requestId", "2021083000002");
        reqParam.put("notifyUrl", "http://test.com");
        reqParam.put("channelType", "wx_scan");
        reqParam.put("amount", "1"); // 单位：分
        reqParam.put("returnUrl", "http://xxxx.com/index");
        reqParam.put("clientIp", "10.101.10.10");
        reqParam.put("gameName", "1区");
        String sign = getSign(reqParam, "721b36ad9af99f2d6c9b334446113a82");
        reqParam.put("code", sign);
        System.out.println(JSONUtil.toJsonStr(reqParam));
        Map<String, String> heads = new HashMap<>();

        heads.put("Content-Type", "application/json;charset=UTF-8");

        HttpResponse response = HttpRequest.post("http://hjkg.hfdervd.com/api/v1/pay/orderWithQr")
                .headerMap(heads, false)
                .body(JSONUtil.toJsonStr(reqParam))
                .timeout(5 * 60 * 1000)
                .execute();
        log.info(response.body());

    }
}
